package util;

import java.io.StringWriter;
import java.util.ArrayList;

import org.codehaus.jettison.AbstractXMLStreamWriter;
import org.codehaus.jettison.mapped.MappedNamespaceConvention;
import org.codehaus.jettison.mapped.MappedXMLStreamWriter;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import bean.*;
import dbConnection.DbConnection;

/**
 * @author tanjian
 * 
 */
public class ItemUtil {

	/**
	 * Put one element under a specific element
	 * 
	 * @param ali
	 * @param element
	 * @param parentItem
	 */
	public static void addElements(ArrayList<Item> ali, Element element,
			Item parentItem) {
		Element subElement;
		// use the addElement method to create a root element catalog.
		for (Item item : ali) {
			if (null == item.getParentItem())
				continue;
			if (item.getParentItem().getName().equals(parentItem.getName())) {
				subElement = element.addElement(item.getName());
				if (null != item.getNodeType()
						&& item.getNodeType().equals("leaf")) {
					subElement.setText(item.getValue());
				}
				addElements(ali, subElement, item);
			}
		}
	}

	/**
	 * Test method.
	 * 
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// System.out.println(WebSearchByRestaurantNamePT.class
		// .getClassLoader().getResource("SearchTestResponse.xml").getPath());
		Document document = XmlUtil.toDOM(CommonInterface.class
				.getClassLoader().getResource("SearchByCityDefinition.xml")
				.getPath());
		document = DOMUtil.parse(DOMUtil.parse(document));
		ArrayList<Item> ali = DOMUtil.toItemList(document);
		// Document doc = setElements(ali);
		// ArrayList<Item> aliNew = getItems(doc);
		printItems(ali, ali.get(0));
		// searchItem(ali, "time", "unavailableTimes").setName("123123123");
		// System.out.println(searchItem(ali, "123123123", "unavailableTimes")
		// .getName());

	}

	/**
	 * Print a item list onto screen
	 * 
	 * @param ali
	 * @throws Exception
	 */
	public static void printItemList(ArrayList<Item> ali) throws Exception {
		if (ali.size() > 0) {
			for (Item item : ali) {
				if (null == item.getParentItem())
					printItems(ali, item);
			}
		}
	}

	/**
	 * Print all sub-items under a specific one onto screen.
	 * 
	 * @param ali
	 * @param parentItem
	 * @throws Exception
	 */
	public static void printItems(ArrayList<Item> ali, Item parentItem)
			throws Exception {
		for (Item item : ali) {
			// ignore the root element
			if (null != item.getParentItem()) {
				// find all those items under the parent item
				if (item.getParentItem().getName().equals(parentItem.getName())) {
					System.out.println(item.getName());
					// only leaf item has valid value
					if (null != item.getNodeType()
							&& item.getNodeType().equals("leaf")) {
						System.out.println(item.getValue());
						continue;
					}
					printItems(ali, item);
				}
			}
		}
	}

	/**
	 * Search for an item in item list by name
	 * 
	 * @param ali
	 * @param name
	 * @return
	 */
	public static Item search(ArrayList<Item> ali, String name) {
		for (Item item : ali) {
			if (null == item.getName()) {
				continue;
			}
			if (item.getName().equals(name)) {
				return item;
			}
		}
		return null;
	}

	/**
	 * Search for an item in item list by its name and parent item
	 * 
	 * @param ali
	 * @param name
	 * @param parentItem
	 * @return
	 */
	public static Item search(ArrayList<Item> ali, String name,
			String parentItem) {
		for (Item item : ali) {
			if (null == item.getParentItem()) {
				continue;
			}
			if (null == item.getParentItem().getName()) {
				continue;
			}
			if (null == item.getName()) {
				continue;
			}
			if (item.getName().equals(name)) {

				if (item.getParentItem().getName().equals(parentItem)) {
					return item;
				}
			}
		}
		return null;
	}

	/**
	 * Returns a item list with items with specified name.
	 * 
	 * @param ali
	 * @param name
	 * @return
	 */
	public static ArrayList<Item> searchItemList(ArrayList<Item> ali,
			String name) {
		ArrayList<Item> aln = new ArrayList<Item>();
		for (Item item : ali) {
			if (null == item.getName()) {
				continue;
			}
			if (item.getName().equals(name)) {
				aln.add(item);
			}
		}
		return aln;
	}

	/**
	 * Put arraylist items to a DOM
	 * 
	 * @param ali
	 * @return
	 */
	public static Document setElements(ArrayList<Item> ali) {
		// create a document with DocumentHelper,DocumentHelper is a factory
		// class which used to produce xml document node.
		Document document = DocumentHelper.createDocument();
		// use the addElement method to create a root element.
		for (Item item : ali) {
			if (null == item.getParentItem()) {
				Element root = document.addElement(item.getName());
				document.setRootElement(root);
				// Iteration to add all other elements.
				addElements(ali, root, item);
			}
		}
		return document;
	}

	/**
	 * Set a item with new value
	 * 
	 * @param ali
	 * @param name
	 * @param parentItem
	 * @param newValue
	 * @return
	 */
	public static ArrayList<Item> setItemValue(ArrayList<Item> ali,
			String name, String parentItem, String newValue) {
		search(ali, name, parentItem).setValue(newValue);
		return ali;
	}

	/**
	 * Item transfer to Json string
	 * 
	 * @param ali
	 * @return
	 * @throws Exception
	 */
	public static String toJson(ArrayList<Item> ali) throws Exception {
		StringWriter strWriter = new StringWriter();

		// Mapped convention
		MappedNamespaceConvention con = new MappedNamespaceConvention();
		AbstractXMLStreamWriter w = new MappedXMLStreamWriter(con, strWriter);
		// use the addElement method to create a root element.
		for (Item item : ali) {
			if (null == item.getParentItem()) {
				w.writeStartDocument();
				w.writeStartElement(item.getName());
				addElements(ali, w, item);
				w.writeEndElement();
				w.writeEndDocument();
			}
		}

		w.close();
		strWriter.close();
		return strWriter.toString();
	}

	/**
	 * Write sub-items to Json
	 * 
	 * @param ali
	 * @param w
	 * @param parentItem
	 * @throws Exception
	 */
	public static void addElements(ArrayList<Item> ali,
			AbstractXMLStreamWriter w, Item parentItem) throws Exception {
		// use the addElement method to create a root element catalog.
		for (Item item : ali) {
			if (null != item.getParentItem()
					&& item.getParentItem().getName()
							.equals(parentItem.getName())) {
				w.writeStartElement(item.getName());
				if (null != item.getNodeType()
						&& item.getNodeType().equals("leaf")) {
					w.writeCharacters(item.getValue());
				}
				addElements(ali, w, item);
				w.writeEndElement();
			}
		}
	}

	public static ArrayList<Item> getItemByCiId(String commonInterfaceId)
			throws Exception {
		Item item = new Item();
		item.setCommonInterfaceId(commonInterfaceId);
		ArrayList<Item> ali = DbConnection.select(item);
		for (Item it : ali) {
			if (null == it.getParentItemId()) {
				continue;
			}
			it.setParentItem(getItemById(it.getParentItemId()));
		}
		return ali;
	}

	public static ArrayList<Item> getItemByType(String commonInterfaceId,
			String type) throws Exception {
		Item item = new Item();
		item.setCommonInterfaceId(commonInterfaceId);
		item.setType(type);
		ArrayList<Item> ali = DbConnection.select(item);
		for (Item it : ali) {
			if (null == it.getParentItemId()) {
				continue;
			}
			it.setParentItem(getItemById(it.getParentItemId()));
		}
		return ali;
	}

	public static Item getItemById(String id) throws Exception {
		Item item = new Item();
		item.setId(id);
		item = DbConnection.getSingle(item);
		if (null != item.getParentItemId()) {
			item.setParentItem(getItemById(item.getParentItemId()));
		}
		return item;
	}

	public static ArrayList<Item> matchItemFromDB(Item item) throws Exception {
		ArrayList<Item> ali = DbConnection.search(item);
		for (Item it : ali) {
			Item condition = new Item();
			condition.setId(it.getParentItemId());
			it.setParentItem(DbConnection.getSingle(condition));
		}
		return ali;
	}

	public static ArrayList<Item> getItemByName(String name) throws Exception {
		Item item = new Item();
		item.setName(name);
		return matchItemFromDB(item);
	}

	public static Item getItemByName(String name, String commonInterfaceId)
			throws Exception {
		Item item = new Item();
		item.setName(name);
		item.setCommonInterfaceId(commonInterfaceId);

		item = DbConnection.getSingle(item);
		if (null != item.getParentItemId()) {
			item.setParentItem(getItemById(item.getParentItemId()));
		}
		return item;
	}

	public static String getItemIdByName(String name, String commonInterfaceId)
			throws Exception {
		Item item = new Item();
		item.setName(name);
		item.setCommonInterfaceId(commonInterfaceId);

		return DbConnection.getSingle(item).getId();
	}
}
